#pragma once

#include "stdafx.h"
#include "FrameRate.h"

namespace ManagedVC1
{
	public ref class ConfigProperties
	{
	private:
		double m_BitRate, m_PeakBitRate;
		unsigned long m_ComplexityLevel, m_QP, m_MaxKeyFrameDistance, m_MaxHeight, m_MaxWidth, 
			m_NumOfBFrames, m_Profile, m_RateControlMode, m_VBVBufferInBytes;
		bool m_InterlacedSource;
		CommonFrameRate^ m_FrameRate;

	public:
		property double BitRate
		{
			double get() { return m_BitRate; }
			void set(double value)
			{
                if (value > 135000 || value == 0) throw gcnew System::ArgumentOutOfRangeException("BitRate must be between 1 and 135000");
				m_BitRate = value;
			}
		}

		property CommonFrameRate^ FrameRate
		{
			CommonFrameRate^ get() { return m_FrameRate; }
			void set(CommonFrameRate^ value)
			{
				m_FrameRate = value;
			}
		}

		property double PeakBitRate
		{
			double get() { return m_PeakBitRate; }
			void set(double value)
			{
				if (value > 135000 || value == 0) throw gcnew System::ArgumentOutOfRangeException("PeakBitRate must be between 1 and 135000");
				m_PeakBitRate = value;
			}
		}

		// TODO must be false when using simple or Main profiles
		property bool InterlacedSource
		{
			bool get() { return m_InterlacedSource; }
			void set(bool value)
			{
				m_InterlacedSource = value;
			}
		}

		property unsigned long ComplexityLevel
		{
			unsigned long get() { return m_ComplexityLevel; }
			void set(unsigned long value)
			{
				if (value > 5) throw gcnew System::ArgumentOutOfRangeException("ComplexityLevel cannot be larger than 5");
				m_ComplexityLevel = value;
			}
		}

		property unsigned long QP
		{
			unsigned long get() { return m_QP; }
			void set(unsigned long value)
			{
				if (value > 31 || value == 0) throw gcnew System::ArgumentOutOfRangeException("QP cannot be larger than 31 or equal to 0");
				m_QP = value;
			}
		}

		// TODO must be greater than or equal to NumofBFrames + 1
		property unsigned long MaxKeyFrameDistance
		{
			unsigned long get() { return m_MaxKeyFrameDistance; }
			void set(unsigned long value)
			{
				m_MaxKeyFrameDistance = value;
			}
		}

		// TODO apply interlaced constraints
		property unsigned long MaxHeight
		{
			unsigned long get() { return m_MaxHeight; }
			void set(unsigned long value)
			{
				if (value > 4096 || value < 64) throw gcnew System::ArgumentOutOfRangeException("MaxHeight must be between 64 and 4096");
				m_MaxHeight = value;
			}
		}

		property unsigned long MaxWidth
		{
			unsigned long get() { return m_MaxWidth; }
			void set(unsigned long value)
			{
				if (value > 4096 || value < 64) throw gcnew System::ArgumentOutOfRangeException("MaxWidth must be between 64 and 4096");
				m_MaxWidth = value;
			}
		}

		// TODO must be zero when using Simple Profile
		property unsigned long NumOfBFrames
		{
			unsigned long get() { return m_NumOfBFrames; }
			void set(unsigned long value)
			{
				if (value > 7) throw gcnew System::ArgumentOutOfRangeException("NumOfBFrames cannot be larger than 7");
				m_NumOfBFrames = value;
			}
		}

		property unsigned long Profile
		{
			unsigned long get() { return m_Profile; }
			void set(unsigned long value)
			{
				if (value > 2) throw gcnew System::ArgumentOutOfRangeException("Profile cannot be larger than 2");
				m_Profile = value;
			}
		}

		property unsigned long RateControlMode
		{
			unsigned long get() { return m_RateControlMode; }
			void set(unsigned long value)
			{
				if (value > 4) throw gcnew System::ArgumentOutOfRangeException("RateControlMode cannot be larger than 4");
				m_RateControlMode = value;
			}
		}


		// TODO The range is 1 to 157696 for Simple profile, 1 to 5001216 for Main profile, and 1 to 33792000 for Advanced profile.
		property unsigned long VBVBufferInBytes
		{
			unsigned long get() { return m_VBVBufferInBytes; }
			void set(unsigned long value)
			{
				//if (value > 5) throw gcnew System::ArgumentException("VBVBufferInBytes cannot be larger than 5");
				m_VBVBufferInBytes = value;
			}
		}

	internal:
		CONFIG_PROPERTIES GetConfigProperties()
		{
			CONFIG_PROPERTIES configProps;
			configProps.dBitRate = m_BitRate;
			configProps.dwComplexityLevel = m_ComplexityLevel;
			configProps.dwQP = m_QP;
			configProps.dFrameRate = m_FrameRate->Rate;
			configProps.bInterlacedSource = m_InterlacedSource;
			configProps.dwMaxKeyFrameDistance = m_MaxKeyFrameDistance;
			configProps.dwMaxHeight = m_MaxHeight;
			configProps.dwMaxWidth = m_MaxWidth;
			configProps.dwNumOfBFrames = m_NumOfBFrames;
			configProps.dPeakBitRate = m_PeakBitRate;
			configProps.dwProfile = m_Profile;
			configProps.dwRateControlMode = m_RateControlMode;
			configProps.dwVBVBufferInBytes = m_VBVBufferInBytes;
			return configProps;
		}
	};
}